﻿using MiniFox.Utility;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace MiniFox
{
    /// <summary>
    /// 序列码
    /// 以此格式 '前缀 + yyyyMMddHHmmss + 尾码 + 后缀' 创建ID, 尾码长度默认为0
    /// 短格式为 '前缀 + yyyyMMdd + 随机尾码 + 后缀' 创建ID, 尾码长度默认为0
    /// 例如: 2015-02-15 12:09:46 , 随机尾码为15(2位随机数)， 最后生成ID -> 2015021512094615 
    /// 例如: 2015-02-15 12:09:46 , 前缀为T, 随机尾码为15(2位随机数), 后缀为901， 最后生成ID -> T2015021512094615901
    /// 例如: 2015-02-15 前缀为R, 尾码为15(2位随机数), 后缀为901， 最后生成ID -> R2015021515901
    /// </summary>
    public class Sequence : IConvertible
    {
        SequenceSetting _setting;
        DateTime _creationTime;
        string _prefix;
        string _suffix;
        string _seqCode;
        string _tailCode;
        /// <summary>
        /// 
        /// </summary>
        protected Sequence() : this(SequenceSetting.CreateDefaultSetting())
        {
        }
        /// <summary>
        /// 使用指定设置创建序列
        /// </summary>
        /// <param name="setting"></param>
        public Sequence(SequenceSetting setting)
        {
            _setting = setting;
            Initialize();

        }
        /// <summary>
        /// 初始化
        /// </summary>
        protected virtual void Initialize()
        {
            DateTime now = Setting.BasedOnUTCTime ? DateTime.UtcNow : DateTime.Now;
            _prefix = Setting.Prefix;
            _suffix = Setting.Suffix;
            _creationTime = now;
            _seqCode = now.ToString(Setting.Pattern);
            if (Setting.TailLength > 0)
                _tailCode = Tools.GenerateRandomCode(Setting.TailLength, Setting.TailCodeType);
        }
        /// <summary>
        /// 
        /// </summary>
        protected SequenceSetting Setting
        {
            get { return _setting; }
        }
        /// <summary>
        /// 
        /// </summary>
        public string Prefix
        {
            get { return _prefix; }
        }
        /// <summary>
        /// 
        /// </summary>
        public string Suffix
        {
            get { return _suffix; }
        }
        /// <summary>
        /// 
        /// </summary>
        public string SeqBaseCode
        {
            get { return _seqCode; }
        }
        /// <summary>
        /// 
        /// </summary>
        public string TailCode
        {
            get { return _tailCode; }
        }
        /// <summary>
        /// 使用默认序列配置创建新的序列编号
        /// </summary>
        /// <returns></returns>
        public static Sequence NewID()
        {
            Sequence seqid = new Sequence();
            return seqid;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <returns>返回带类型和日期前缀的ID号</returns>
        public override string ToString()
        {
            StringBuilder seq = new StringBuilder();
            //添加前缀
            seq.Append(Prefix);
            //添加日期码
            seq.Append(SeqBaseCode);
            //添加尾码
            seq.Append(TailCode);
            //添加后缀
            seq.Append(Suffix);

            return seq.ToString();
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="seq"></param>
        /// <returns></returns>
        public static implicit operator string(Sequence seq)
        {
            if (seq == null)
                return null;

            return seq.ToString();
        }
        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        public TypeCode GetTypeCode()
        {
            return TypeCode.Object;
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="provider"></param>
        /// <returns></returns>
        public bool ToBoolean(IFormatProvider provider)
        {
            return string.Equals(ToString(), string.Empty, StringComparison.OrdinalIgnoreCase);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="provider"></param>
        /// <returns></returns>
        public byte ToByte(IFormatProvider provider)
        {
            return byte.MinValue;
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="provider"></param>
        /// <returns></returns>
        public char ToChar(IFormatProvider provider)
        {
            return char.MinValue;
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="provider"></param>
        /// <returns></returns>
        public DateTime ToDateTime(IFormatProvider provider)
        {
            return _creationTime;
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="provider"></param>
        /// <returns></returns>
        public decimal ToDecimal(IFormatProvider provider)
        {
            return decimal.Zero;
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="provider"></param>
        /// <returns></returns>
        public double ToDouble(IFormatProvider provider)
        {
            return 0.0d;
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="provider"></param>
        /// <returns></returns>
        public short ToInt16(IFormatProvider provider)
        {
            return 0;
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="provider"></param>
        /// <returns></returns>
        public int ToInt32(IFormatProvider provider)
        {
            return 0;
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="provider"></param>
        /// <returns></returns>
        public long ToInt64(IFormatProvider provider)
        {
            return 0;
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="provider"></param>
        /// <returns></returns>
        public sbyte ToSByte(IFormatProvider provider)
        {
            return 0;
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="provider"></param>
        /// <returns></returns>
        public float ToSingle(IFormatProvider provider)
        {
            return 0.0f;
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="provider"></param>
        /// <returns></returns>
        public string ToString(IFormatProvider provider)
        {
            return ToString();
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="conversionType"></param>
        /// <param name="provider"></param>
        /// <returns></returns>
        public object ToType(Type conversionType, IFormatProvider provider)
        {
            if (conversionType == typeof(string))
            {
                return ToString();
            }
            else
            {
                return null;
            }
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="provider"></param>
        /// <returns></returns>
        public ushort ToUInt16(IFormatProvider provider)
        {
            return 0;
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="provider"></param>
        /// <returns></returns>
        public uint ToUInt32(IFormatProvider provider)
        {
            return 0;
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="provider"></param>
        /// <returns></returns>
        public ulong ToUInt64(IFormatProvider provider)
        {
            return 0;
        }
    }
    /// <summary>
    /// 创建序列所使用的设置，默认按UTC时间匹配，无前缀 无后缀 无尾码
    /// </summary>
    public class SequenceSetting
    {
        string _pattern;
        string _prefix;
        string _suffix;
        byte _tailLength;
        bool _basedOnUTC;
        CodeType _codeType;
        /// <summary>
        /// 
        /// </summary>
        private SequenceSetting() : this("yyyyMMddHHmmss")
        {
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="pattern"></param>
        public SequenceSetting(string pattern) : this(pattern, true)
        {
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="pattern"></param>
        /// <param name="basedOnUtc"></param>
        public SequenceSetting(string pattern, bool basedOnUtc) : this(string.Empty, string.Empty, pattern, 0, basedOnUtc, CodeType.Number)
        {
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="prefix">序列前缀</param>
        /// <param name="suffix">序列后缀</param>
        /// <param name="pattern">日期匹配格式(默认为: yyyyMMddHHmmss)</param>
        /// <param name="tailLength">随机尾码长度</param>
        /// <param name="basedOnUTC">是否基于UTC时间创建序列码</param>
        /// <param name="tailCodeType">指定随机尾码类型</param>
        public SequenceSetting(string prefix, string suffix, string pattern, byte tailLength, bool basedOnUTC, CodeType tailCodeType)
        {
            _prefix = prefix;
            _suffix = suffix;
            _pattern = pattern;
            _tailLength = tailLength;
            _basedOnUTC = basedOnUTC;
            _codeType = tailCodeType;
        }
        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        internal static SequenceSetting CreateDefaultSetting()
        {
            return new SequenceSetting();
        }
        /// <summary>
        /// 前缀
        /// </summary>
        public string Prefix
        {
            get { return _prefix; }
        }
        /// <summary>
        /// 后缀
        /// </summary>
        public string Suffix
        {
            get { return _suffix; }
        }
        /// <summary>
        /// 随机尾码长度(为0是不启用)
        /// </summary>
        public byte TailLength
        {
            get { return _tailLength; }
        }
        /// <summary>
        /// 随机尾码类型，默认为数字类型(数字|字母|混合字符, 注意:不包含特殊字符)
        /// </summary>
        public CodeType TailCodeType
        {
            get { return _codeType; }
        }
        /// <summary>
        /// 
        /// </summary>
        public string Pattern
        {
            get { return _pattern; }
        }
        /// <summary>
        /// 是否基于UTC时间生成
        /// </summary>
        public bool BasedOnUTCTime
        {
            get { return _basedOnUTC; }
        }
    }
}
